//////////////////////////////////////////ok
#include"stdafx.h"
#include "bochs.h"



Bit16u  IA32_CPU::inp16(Bit16u addr)
{
  Bit16u ret16;

  if ( cr0.pe && ( get_VM () || (CPL> get_IOPL ()))) 
  {
    if ( ! allow_io(addr, 2) ) 
	{
      exception(IA32_GP_EXCEPTION, 0, 0);
      return(0);
    }

  }

  ret16=0;
 // ret16 = BX_INP(addr, 2);

  return( ret16 );
}


void  IA32_CPU::outp16(Bit16u addr, Bit16u value)
{

  if ( cr0.pe && ( get_VM() || (CPL> get_IOPL()))) 
  {
    if ( ! allow_io(addr, 2) ) 
	{
      exception(IA32_GP_EXCEPTION, 0, 0);
      return;
    }
  }
 
  // BX_OUTP(addr, value, 2);

}

Bit32u  IA32_CPU::inp32(Bit16u addr)
{
  Bit32u ret32;

  if ( cr0.pe && ( get_VM() || (CPL> get_IOPL()))) 
  {
    if ( ! allow_io(addr, 4) ) 
	{
      exception(IA32_GP_EXCEPTION, 0, 0);
      return(0);
    }
  }

  ret32=0;
 // ret32 = BX_INP(addr, 4);
 
  return( ret32 );
}

void  IA32_CPU::outp32(Bit16u addr, Bit32u value)
{

  if ( cr0.pe && ( get_VM() || (CPL> get_IOPL()))) 
  {
    if ( ! allow_io(addr, 4) ) 
	{
      exception(IA32_GP_EXCEPTION, 0, 0);
      return;
    }
  }

//  BX_OUTP(addr, value, 4);

}

Bit8u  IA32_CPU::inp8(Bit16u addr)
{
  Bit8u ret8;

  if ( cr0.pe && ( get_VM() || (CPL> get_IOPL()))) 
  {
    if ( ! allow_io(addr, 1) ) 
	{
      exception(IA32_GP_EXCEPTION, 0, 0);
      return(0);
    }
  }

  ret8=0;
//  ret8 = BX_INP(addr, 1);

  return( ret8 );
}


void  IA32_CPU::outp8(Bit16u addr, Bit8u value)
{

  if ( cr0.pe && ( get_VM() || (CPL> get_IOPL()))) 
  {
    if ( ! allow_io(addr, 1) ) 
	{
      exception(IA32_GP_EXCEPTION, 0, 0);
      return;
    }
  }

  //BX_OUTP(addr, value, 1);

}

bx_bool IA32_CPU::allow_io(Bit16u addr, unsigned len)
{
  Bit16u io_base, permission16;
  unsigned bit_index, i;

  if ( tr.cache.valid==0 ||  tr.cache.type != IA32_SYS_SEGMENT_AVAIL_386_TSS)
  {
    return(0);
  }

  if ( tr.cache.u.tss386.limit_scaled < 103) 
  {
    return(0);
  }

  m_vm32->access_address_n(this, tr.cache.u.tss386.base + 102,2, 0, IA32_READ, &io_base);
#ifdef IA32_BIG_ENDIAN
  IA32_ReadHostWordFromLittleEndian(&io_base, &io_base);
#endif
  if (io_base <= 103) 
  {
     return(0);
  }

  if ( (Bit32s) (addr/8) >= (Bit32s) ( tr.cache.u.tss386.limit_scaled - io_base)) 
  {
    return(0);
  }

  m_vm32->access_address_n(this, tr.cache.u.tss386.base + io_base + addr/8, 2, 0, IA32_READ, &permission16);
#ifdef IA32_BIG_ENDIAN
  IA32_ReadHostWordFromLittleEndian(&permission16, &permission16);
#endif
  bit_index = addr & 0x07;
  permission16 >>= bit_index;
  for (i=0; i<len; i++) 
  {
    if (permission16 & 0x01)
      return(0);
    permission16 >>= 1;
  }

  return(1);
}
